package mongo

import (
	"context"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"mongoDemo/common"
	"mongoDemo/parameter"
)

type Mongo struct {
	db *mongo.Database
}

func NewMongo() *Mongo {
	return &Mongo{db: common.NewMongo()}
}

type blockchainDoc struct {
	CourseId       string `bson:"courseId"`
	MicroserviceId string `bson:"microserviceId"`
	Vendor         string `bson:"vendor"`
	DateTime       string `bson:"dateTime"`
	Scores         []any  `bson:"scores"`
	Comment        string `bson:"comment"`
	User           string `bson:"user"`
	Hash           string `bson:"hash"`
}

func (m *Mongo) DeleteBlockchain(parameter parameter.InitParameter) error {
	filter := bson.M{"$and": []bson.M{
		{"courseId": parameter.CourseId},
		{"microserviceId": parameter.MicroserviceId},
		{"vendor": parameter.Vendor},
		{"user": parameter.User},
	}}
	_, err := m.db.Collection("blockchain").DeleteMany(context.TODO(), filter)
	return err
}

func (m *Mongo) AddBlockchain(parameter parameter.InitParameter) error {
	filter := bson.D{
		{"courseId", parameter.CourseId},
		{"microserviceId", parameter.MicroserviceId},
		{"vendor", parameter.Vendor},
		{"dateTime", parameter.DateTime},
		{"scores", parameter.Scores},
		{"comment", parameter.Comment},
		{"user", parameter.User},
		{"hash", parameter.Hash},
	}
	_, err := m.db.Collection("blockchain").InsertOne(context.TODO(), filter)
	return err
}

func (m *Mongo) GetScores() ([]parameter.ScoreParameter, error) {
	result, err := m.db.Collection("blockchain").Find(context.TODO(), bson.M{})
	scores := make([]parameter.ScoreParameter, 0)
	for result.Next(context.TODO()) {
		var doc blockchainDoc
		innerErr := result.Decode(&doc)
		if innerErr == nil {
			scores = append(scores, parameter.ScoreParameter{
				CourseId:       doc.CourseId,
				MicroserviceId: doc.MicroserviceId,
				DateTime:       doc.DateTime,
				Scores:         doc.Scores,
				Comment:        doc.Comment,
				User:           doc.User,
				Hash:           doc.Hash,
			})
		}
	}
	return scores, err
}

func (m *Mongo) QueryByMicroserviceId(microserviceId string, user string) ([]parameter.ScoreParameter, error) {
	filter := bson.M{"$and": []bson.M{{"microserviceId": microserviceId}, {"user": user}}}
	opts := options.Find().SetSort(bson.D{{"dateTime", -1}})
	if microserviceId == "" && user != "" {
		filter = bson.M{"user": user}
	} else if microserviceId != "" && user == "" {
		filter = bson.M{"microserviceId": microserviceId}
	} else if microserviceId == "" && user == "" {
		filter = nil
	}
	result, err := m.db.Collection("blockchain").Find(context.TODO(), filter, opts)
	scores := make([]parameter.ScoreParameter, 0)
	for result.Next(context.TODO()) {
		var doc blockchainDoc
		innerErr := result.Decode(&doc)
		if innerErr == nil {
			scores = append(scores, parameter.ScoreParameter{
				CourseId:       doc.CourseId,
				MicroserviceId: doc.MicroserviceId,
				DateTime:       doc.DateTime,
				Scores:         doc.Scores,
				Comment:        doc.Comment,
				User:           doc.User,
				Hash:           doc.Hash,
			})
		}
	}
	return scores, err
}
